#ifndef REF_HPP
#define REF_HPP

#include <cstdio>
#include <iostream>
#include <memory>
#include <utility>

namespace ref {
struct TRef {
  char *before;
  char &ref;
  char *after;
};

void test1() {
  char a = 'a';
  char &b = a;
  char c = 'c';
  TRef r = {&a, b, &c};
  printf("sizeof(r) = %lu\n", sizeof(r));
  printf("sizeof(r.before) = %lu\n", sizeof(r.before));
  printf("sizeof(r.after) = %lu\n", sizeof(r.after));
  printf("sizeof(r.ref) = %lu\n", sizeof(*&(r.ref)));
  printf("&r.before = %p\n", &r.before);
  printf("&r.after = %p\n", &r.after);
  printf("&r.after = %p\n", &r.ref);
}

// x 不是转发引用：const T 不是无 cv 限定的
template <class T> int g(T &&x) {
  std::cout << std::is_lvalue_reference<T>() << std::is_rvalue_reference<T>()
            << std::endl;
  std::cout << "x:" << x << ", " << typeid(T).name() << std::endl;
  return 0;
}

template <class T> int f(T &&x) { // x 是转发引用
  return g(std::forward<T>(x));   // 从而能被转发
}
void test2() {
  int i;
  f(i); // 实参是左值，调用 f<int&>(int&), std::forward<int&>(x) 是左值
  f(0); // 实参是右值，调用 f<int>(int&&), std::forward<int>(x) 是右值
}

struct Arg {
  int i = 1;
  int get() && {
    std::cout << __FUNCTION__ << __LINE__ << std::endl;
    return i;
  } // 此重载的调用为右值
  int &get() & {
    std::cout << __FUNCTION__ << __LINE__ << std::endl;
    return i;
  } // 此重载的调用为左值
};

void test3() {
  Arg arg;
  std::cout << arg.get() << std::endl;
  Arg &argr = arg;
  std::cout << argr.get() << std::endl;
  // Arg &&argrr = Arg{1};
  std::cout << Arg{1}.get() << std::endl;
}

struct A {
  A(int &&n) { std::cout << "rvalue overload, n=" << n << "\n"; }
  A(int &n) { std::cout << "lvalue overload, n=" << n << "\n"; }
};

class B {
public:
  template <class T1, class T2, class T3>
  B(T1 &&t1, T2 &&t2, T3 &&t3)
      : a1_{std::forward<T1>(t1)}, a2_{std::forward<T2>(t2)},
        a3_{std::forward<T3>(t3)} {}

private:
  A a1_, a2_, a3_;
};

template <class T, class U> std::unique_ptr<T> make_unique1(U &&u) {
  std::cout << std::is_lvalue_reference<U>() << std::is_rvalue_reference<U>()
            << std::endl;
  return std::unique_ptr<T>(new T(std::forward<U>(u)));
}

template <class T, class... U> std::unique_ptr<T> make_unique2(U &&... u) {
  // std::cout << std::is_lvalue_reference<U>() << std::is_rvalue_reference<U>()
  //           << std::endl;
  return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}

void test4() {
  auto p1 = make_unique1<A>(2); // 右值 make_unique1<A, int>
  int i = 1;
  auto p2 = make_unique1<A>(i); // 左值 make_unique1<A, int&>

  std::cout << "B\n";
  auto t = make_unique2<B>(2, i, 3);
}

[[noreturn]] void f1 [[noreturn]] ();
// void f2() [[noreturn]];
void f3 [[deprecated("reason")]] () { 
  std::cout << __FUNCTION__ << __LINE__ << std::endl;
}

void test5() {
  f3();
}

} // namespace ref

void ref_demo() { ref::test5(); }

#endif // REF_HPP